var event = require('../../core/event');
var util = require('../../util/index');
var notify = require('../notify/ui');
var Log = require('../../util/logger');
var io = require('../io/ui');
var path = require('path');
var fs = require('fs');
var enums = require('../../core/enum');
var config = require('../../core/config');


var loadedFile = {};
var _init = false;

/**
 * 这个类负责管理note文件的加载，保存，对外提供note文件整体
 * 不负责note文件的内容控制，不关心文件内部逻辑
 *
 * 虽然设计上支持多实例, 但目前很多功能是按单实例实现的, 请留意
 */
var ret = {
	MODE: {
		KEY: 0,
		STEP: 1,
		DJ: 2,
		CATCH: 3,
        UBEAT: 4,
		TAIKO : 5
	},

	init: function(){
		if(_init){
			return;
		}

		this.saveTimer = null;
		this.dirty = false;

		event.bindOwner("file", 'note',this);
		event.bind(event.events.note.change, 'note', this);
		event.bind(event.events.global.drop, 'note', this);

		_init = true;
		Log.log("note init");
	},

	onEvent: function(e, params){
		var self = this;
		params = params || {};
		if(e == event.events.file.load){
			io.getChartPath().then(function(file){
				if(file){
					self.load(file, "main");
				}
			})
		}else if(e == event.events.file.save){
			var key = params.savekey || 'main';
			var file = loadedFile[key];
			if(!file){
				return;
			}
			if(file.path){
				self.save(key, true, true);
			}else{
				io.getSavePath().then(function(filename){
					filename = util.ensureSuffix(filename, 'mce');
					if(filename){
						file.path = filename;
						self.save(key, true, true);
					}
				});
			}
		}else if(e == event.events.file.saveas){
			var key = params.savekey || 'main';
			var file = loadedFile[key];
			if(!file){
				return;
			}
			io.getSavePath().then(function(filename){
				if(filename){
					filename = util.ensureSuffix(filename, 'mce');
					self.saveas(key, filename);
				}
			});
		}else if(e == event.events.file.unload) {
			var key = params.savekey || 'main';
			this.unload(key);
			clearTimeout(this.saveTimer);
			event.trigger(event.events.dialog.welcome);
		}else if(e == event.events.global.drop){
			//param不用验
			var arr = params.dataTransfer.files;f
			if(arr.length == 1){
				var ext = path.extname(arr[0]);
				if(ext == '.mce' || ext == '.mc'){
					this.save();
					this.unload();
					this.load(arr[1]);
					return event.result.stopAll;
				}
			}
		}else if(e == event.events.file.exports) {
			var key = params.savekey || 'main';
			this.exportChart(key);
		}else if(e == event.events.file.imports){
			io.getAny().then(function(filename) {
				if(filename){
					self.importChart(filename);
				}
			})
		}else if(e == event.events.note.change){
			this.dirty = true;
		}else if(e == event.events.file.importmeta){
			this.importMeta();
		}else if(e == event.events.file.mc2bms){
			var key = params.savekey || 'main';
			this.exportBMS(key);
		}
	},

	load: function(filename, savekey){
		if(!savekey){
			savekey = 'main';
		}
		var self = this;
		util.loadJson(filename).then(function(content){
			self.afterLoad(content, filename);
			notify.addNotify({msg:'Load '+filename});
			self.dirty = true;
		});
	},

	save: function(savekey, force, exports){
		if(!savekey){
			savekey = 'main';
		}
		var target = loadedFile[savekey];
		if(!target || !target.path){
			return;
		}
		var self = this;
		target.content.meta.time = Math.floor(Date.now() / 1000);  //更新最后编辑时间
		if(force){
			util.saveJsonSync(target.path, target.content);
			self.dirty = false;
			notify.addNotify({msg:'Save successful!'});
		}else{
			util.saveJson(target.path, target.content).then(function(e){
				notify.addNotify({msg:'Save successful!'});
				notify.changeActionDisplay('edit','Editing:'+path.basename(target.path));
				self.dirty = false;
			}).catch(function(e){
				event.trigger(event.events.note.err, 'save failed');
			});
		}
		if(exports){
			this.exportUpload(); //得到一份mc
		}
	},

	saveas: function(savekey, filename){
		if(!savekey){
			savekey = 'main';
		}
		var target = loadedFile[savekey];
		if(!target){
			return;
		}
		var copy = util.cloneObject(target.content);
		util.setJsonChainValue(copy, "meta.id", 0);
		util.setJsonChainValue(copy, "meta.song.id", 0);
		util.saveJson(filename, copy).then(function(e){
			notify.addNotify({msg:'Save successful!'});
		}).catch(function(e){
			event.trigger(event.events.note.err, 'save failed');
		});
	},

	importChart: function(filename){
		var suffix = path.extname(filename);
		var converter = null;
		if(suffix == '.bms' || suffix == '.bme'){
			converter = require('./import/bms.js');
		}else if(suffix == ".osu"){
            converter = require('./import/osu.js');
        }else if(suffix == ".txt"){
            converter = require('./import/ubt_analyser.js');
        }else if(suffix == ".imd"){
            converter = require('./import/imd.js');
        }
		if(!converter){
			notify.addNotify({
				msg: config.i18n("err21")
			});
			return;
		}
		var self = this;
		self.save('main');
		self.unload('main');
		var note = converter.getNote(filename);
		if(!note) {
			return;
		}
		filename = util.ensureSuffix(filename, 'mce');
		util.saveJsonSync(filename, note);
		self.afterLoad(note, filename);
		notify.addNotify({msg:'Import '+filename});
	},

	importMeta: function(){
		var target = loadedFile['main'];
		if(!target){
			return;
		}
		var curr = target.content;
		if(!window.confirm(config.i18n("readme04"))){
			return;
		}
		io.getChartPath().then(function(file){
			if(!file){
				return;
			}
			if(file == target.path){
				return;
			}
			event.trigger(event.events.note.unload, 'main');
			return util.loadJson(file);
		}).then(function(content){
			curr.meta.creator = content.meta.creator;
			curr.meta.cover = content.meta.cover;
			curr.meta.background = content.meta.background;
			curr.meta.song = util.cloneObject(content.meta.song);
			curr.meta.song.id = 0;

			notify.addNotify({msg: 'Update meta successful!'});
			event.trigger(event.events.note.load, {
				key: 'main',
				path: target.path
			});
			notify.changeActionDisplay('edit', "Editing:"+path.basename(target.path));
		}).catch(function(e){

		});
	},

	/**
	 * 导出, 会对参数做严格过滤和化简
	 * 并且移动相关文件
	 */
	exportChart: function(savekey){
		if(!savekey){
			savekey = 'main';
		}
		var target = loadedFile[savekey];
		if(!target){
			return;
		}
		var assit = require('./export/export');
		assit.setManager(this);
		assit.doExport(target);
	},

	exportBMS : function(savekey){
		if(!savekey){
			savekey = 'main';
		}
		var target = loadedFile[savekey];
		if(!target){
			return;
		}
		var assit = require('./export/export');
		assit.setManager(this);
		assit.doExportBMS(target);
	},

	/**
	 * 用于测试的导出
	 * @param dir
	 * @returns {*}
	 */
	exportTest: function(dir) {
		var target = loadedFile['main'];
		if(!target){
			return;
		}
		var assit = require('./export/export');
		assit.setManager(this);
		return assit.doTestExport(target, dir);
	},

	exportUpload: function () {
		var target = loadedFile['main'];
		if(!target){
			return;
		}
		var assit = require('./export/export');
		assit.setManager(this);
		return assit.doUploadExport(target);
	},

	autosave: function(){
		if(!this.dirty){
			return;
		}
		this.save();
		this.saveTimer = setTimeout(this.autosave.bind(this), 60*1000);
	},

	afterLoad: function(note, filename){
		var isMCE = filename.indexOf('.mce') > 0;
		if(!isMCE){
			filename = util.ensureSuffix(filename, 'mce'); //自动另存为mce格式
		}
		this.validate(note);
		loadedFile['main'] = {
			content: note,
			path: filename
		};
		notify.showWaiting(true);
		setTimeout(function() {
			event.trigger(event.events.note.load, {
				key: 'main',
				path: filename
			});
			notify.showWaiting(false);
		}, 50);  //照例50ms等待ui时间

		this.basedir = path.dirname(filename) + '/';
		notify.changeActionDisplay('edit', "Editing:"+path.basename(filename));
		this.saveTimer = setTimeout(this.autosave.bind(this), 60*1000);
	},

	/**
	 * 制造一个新的，替换对应的note obj
	 */
	createNew: function(basic, file, savekey){
		if(!savekey){
			savekey = 'main';
		}
		if(loadedFile[savekey]){
			this.unload(savekey);
		}
		var data = util.cloneObject(require('../../data/template.json'));
		this.updateMeta(data, basic);

		file = util.ensureSuffix(file, 'mce');
		this.afterLoad(data, file);
	},

	updateMeta: function (target, meta) {
		util.setJsonChainValue(target, 'meta.song.title', meta.title);
		util.setJsonChainValue(target, 'meta.song.artist', meta.artist);
		util.setJsonChainValue(target, 'meta.song.source', meta.source);

		util.setJsonChainValue(target, 'meta.song.org.title', meta.title2);
		util.setJsonChainValue(target, 'meta.song.org.artist', meta.artist2);
		util.setJsonChainValue(target, 'meta.song.org.source', meta.source2);

		target.meta.background = meta.background || '';
		target.meta.creator = meta.creator;
		target.meta.version = meta.version;
		target.meta.mode = +meta.mode || 0;
		if(target.meta.mode == 3){
			util.setJsonChainValue(target, 'meta.mode_ext.speed', +meta.speed || 5);
		}else if(target.meta.mode == 4){
            util.setJsonChainValue(target, 'meta.mode_ext.interval', +meta.interval || 1.035);
		}else{
            util.setJsonChainValue(target, 'meta.mode_ext.column', +meta.column || 4);
        }
	},

	updateBG: function(file){
		var target = loadedFile["main"];
		if(!target){
			return;
		}
		this.importFile(file, true);
		target.content.meta.background = path.basename(file);
	},

	unload: function(savekey){
		if(!savekey){
			return;
		}
		if(!loadedFile[savekey]){
			return;
		}
		delete loadedFile[savekey];
		this.basedir = null;
		event.trigger(event.events.note.unload, savekey);
		notify.changeActionDisplay('edit', '');
	},

	/**
	 * 验证chart的各项参数, 如果没有, 就补上默认值
	 * 经过这个函数处理后, 内部其他模块可以适当放宽异常检查
	 * @param chart
	 */
	validate: function (chart) {
		util.ensureJsonValue(chart, 'meta', {});
		util.ensureJsonValue(chart, 'time', []);
		util.ensureJsonValue(chart, 'note', []);
		util.ensureJsonValue(chart, 'extra', {});
		util.ensureJsonValue(chart, 'meta.mode_ext', {});

        if(chart.meta.mode == 4){
            util.ensureJsonValue(chart, 'extra.toggle', [2,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0]);
            util.ensureJsonValue(chart, 'meta.mode_ext.column', 1);
        }
		//debugger;
		if(chart.meta.mode < 3){
			util.ensureJsonValue(chart, 'extra.toggle', []);

			if(chart.extra.toggle.length != 15){
				var exist = [0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0]; //15个
				if(chart.note.length){
					var col = 0;
					for(var i=0;i<chart.note.length;i++){
						var note = chart.note[i];
						if(!exist[note.column]){
							//fixme: 如果同轨道既有普通note 也有 sound, 是错误情况, 这里忽略
							if(note.type == 1){
								exist[note.column] = 2;
								if(note.column > col){
									col = note.column;
								}
							}else{
								exist[note.column] = 1;
							}
						}
					}
					util.ensureJsonValue(chart, 'meta.mode_ext.column', col + 1);
				}else{
					util.ensureJsonValue(chart, 'meta.mode_ext.column', 4);
					var col = chart.meta.mode_ext.column;
					for(var i=0;i<col;i++){
						exist[i] = 1;
					}
					exist[col] = 2;
				}

				chart.extra.toggle = exist;
			}
		}
	},

	/**
	 * obj返回之后可以在外部修改，也可以用update方法写回来
	 */
	getNote: function(savekey){
		var obj = loadedFile[savekey];
		if(obj){
			return obj.content;
		}
		return null;
	},

	/**
	 * 得到所有引用的文件, 包括自己
	 * @param savekey
	 */
	getAllFiles: function (savekey) {
		if(!savekey){
			return;
		}
		if(!loadedFile[savekey]){
			return;
		}
		var target = loadedFile[savekey];
		var ret = [];
		ret.push(path.basename(target.path));
		var notes = target.note;
		for(var i=0;i<notes.length;i++){
			if(notes[i].sound){
				ret.push(notes[i].sound);
			}
		}
		if(target.background){
			ret.push(target.background);
		}
		return ret;
	},

	/**
	 * 得到所有引用的文件, 包括自己, 绝对地址
	 * @param savekey
	 */
	getAllFileAbs: function (savekey) {
		if(!savekey){
			return;
		}
		if(!loadedFile[savekey]){
			return;
		}
		var target = loadedFile[savekey];
		var ret = [];
		ret.push(target.path);
		var notes = target.content.note;
		var sounds = {};
		for(var i=0;i<notes.length;i++){
			if(notes[i].sound){
				sounds[notes[i].sound] = true;
			}
		}
		var keys = Object.keys(sounds);
		for(var i=keys.length-1;i>=0;i--){
			var _path = this.basedir + keys[i];
			if(fs.existsSync(_path)){
				ret.push(_path);
			}
		}
		if(target.content.meta.background){
			ret.push(this.basedir + target.content.meta.background);
		}
		return ret;
	},

	/**
	 * 把一个外部文件复制到谱面同目录下
	 * @param file
	 */
	importFile: function(file, sync) {
		if(!this.basedir){
			return;
		}
		var name = path.basename(file);
		util.copyFile(file, path.join(this.basedir, name), false, sync);
	},

	getFilePath: function(file){
		if(!this.basedir){
			return;
		}
		return path.join(this.basedir,  file).replace(/\\/g,"/");
	}
};

module.exports = ret;
